package com.zhongan.gateway.common.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class Counter {
    private Map<String, AtomicInteger> count;

    private Map<String, Long>          timestamp;

    private Thread                     monitor;

    private long                       interval;

    private long                       timeout;

    private boolean                    running;

    public Counter(long intervalSeconds) {
        this.count = new ConcurrentHashMap<String, AtomicInteger>();
        this.timestamp = new ConcurrentHashMap<String, Long>();
        this.monitor = new Thread(new Monitor());
        this.monitor.start();
        this.interval = intervalSeconds * 1000;
        this.timeout = interval << 1;

        this.running = true;
    }

    private class Monitor implements Runnable {

        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(20000L);
                } catch (InterruptedException e) {
                    running = false;
                    break;
                }
                List<String> keys = new ArrayList<String>();
                for (String key : timestamp.keySet()) {
                    Long ts = timestamp.get(key);
                    if (now() - ts > timeout) {
                        keys.add(key);
                    }
                }
                for (String key : keys) {
                    timestamp.remove(key);
                    count.remove(key);
                }
            }
        }
    }

    public void stop() {
        this.monitor.interrupt();
    }

    public int hit(String key, int max) {
        if (!running) {
            return 0;
        }
        Long ts = timestamp.get(key);
        long now = now();
        if (ts == null) { // new key
            timestamp.put(key, now);
            count.put(key, new AtomicInteger());
        } else { // old key
            if (now - ts > interval) { // expired key
                timestamp.put(key, now);
                count.put(key, new AtomicInteger());
            }
        }
        AtomicInteger i = count.get(key);
        int c = 1;
        if (i != null) {
            c = i.incrementAndGet();
        }
        return c <= max ? c : -c;
    }

    private long now() {
        return System.currentTimeMillis();
    }

}
